using System;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;

namespace Camalon.Drawing
{
	/// <summary>
	/// Represents an ordered pair of integer x- and y-coordinates that defines a point 
	/// in a two-dimensional plane. The point can anchored to the edges of its container.  
	/// </summary>
	/// <remarks>
	/// A point can be anchored to one or more edges of its parent container. Anchoring a point 
	/// to its parent ensures that the anchored point remain in the same position relative to the 
	/// edges of the parent container when the parent container is resized.
	/// </remarks>
	[Serializable]
	[TypeConverter(typeof(AnchorPointConverter))]
	public struct AnchorPoint
	{
		private Point _point;
		private AnchorStyles _anchor;

        /// <summary>
        /// Initializes a new instance of the Point class from a Point and AnchorStyles.
        /// </summary>
        /// <param name="point">A Point that specifies the coordinates for the new AnchorPoint.</param>
        /// <param name="anchor">A bitwise combination of the <c>AnchorStyles</c> values. The default is Top and Left.</param>
		public AnchorPoint(Point point, AnchorStyles anchor )
		{
			_point = point;
			_anchor = anchor;
		}

		/// <summary>
		/// Initializes a new instance of the AnchorPoint class with the specified coordinates and AnchorStyles.
		/// </summary>
		/// <param name="x">The horizontal position of the point.</param>
		/// <param name="y">The vertical position of the point.</param>
		/// <param name="anchor">A bitwise combination of the AnchorStyles values. </param>
		public AnchorPoint(int x, int y, AnchorStyles anchor )
		{
			_point = new Point( x,y );
			_anchor = anchor;
		}


		/// <summary>
		/// Initializes a new instance of the AnchorPoint class from a Point.
		/// </summary>
		/// <param name="point">A Point that specifies the coordinates for the new AnchorPoint.</param>
		public AnchorPoint(Point point):this( point, AnchorStyles.Top|AnchorStyles.Left){}

		/// <summary>
		/// Initializes a new instance of the AnchorPoint class with the specified coordinates.
		/// </summary>
		/// <param name="x">The horizontal position of the point.</param>
		/// <param name="y">The vertical position of the point.</param>
		public AnchorPoint(int x, int y ):this( x,y, AnchorStyles.Top|AnchorStyles.Left){}

		/// <summary>
		/// Represents a null AnchorPoint.
		/// </summary>
		[Browsable(false)]
		public static AnchorPoint Empty
		{
			get{ return new AnchorPoint(0,0, AnchorStyles.None);}
		}

		/// <summary>
		/// Gets a value indicating whether this AnchorPoint is empty.
		/// </summary>
		/// <remarks>This property returns true if both X and Y are zero and AnchorStyles is none; otherwise, false.</remarks>
		[Browsable(false)]
		public bool IsEmpty
		{
			get{ return _point.IsEmpty && _anchor == AnchorStyles.None;}
		}

		/// <summary>
		/// Gets a value indicating the default values of an AnchorPoint.
		/// </summary>
		/// <remarks>Default is a null(Empty) point that is anchored to the Top-Left edge of its container  </remarks>
		[Browsable(false)]
		public static AnchorPoint Default
		{
			get{ return new AnchorPoint(0,0,AnchorStyles.Top|AnchorStyles.Left);}
		}

		/// <summary>
		/// Gets a value indicating whether this AnchorPoint is default.
		/// </summary>
		/// <remarks>This property returns true if this is a null(Empty) point that is anchored to the Top-Left edge of its container; otherwise, false.</remarks>
		[Browsable(false)]
		public bool IsDefault
		{
			get{ return _point.IsEmpty && _anchor == (AnchorStyles.Top|AnchorStyles.Left);}
		}

		/// <summary>
		/// Gets or sets the x-coordinate of this AnchorPoint.
		/// </summary>
		[DefaultValue(0)]
		public int X
		{
			get{ return _point.X;}
			set{ _point.X = value;}
		}

		/// <summary>
		/// Gets or sets the y-coordinate of this AnchorPoint.
		/// </summary>
		[DefaultValue(0)]
		public int Y
		{
			get{ return _point.Y;}
			set{ _point.Y = value;}
		}

		internal static  bool ValidateAnchor( AnchorStyles anchor )
		{
			if( (anchor & AnchorStyles.Right  ) > 0 && (anchor & AnchorStyles.Left) > 0) 
			{
				return false;
				//anchor &=~AnchorStyles.Right;
			}

			if( (anchor & AnchorStyles.Top  ) > 0 && (anchor & AnchorStyles.Bottom) > 0) 
			{
				return false;
				//anchor &=~AnchorStyles.Bottom;
			}

			return true;
			//return anchor;
		}


		/// <summary>
		/// A bitwise combination of the AnchorStyles values. The default is Top and Left.
		/// </summary>
		[DefaultValue( AnchorStyles.Top|AnchorStyles.Left )]
		public AnchorStyles Anchor
		{
			get{ return _anchor;}
			set
			{
				if(!ValidateAnchor( value)) return;

				_anchor = value; 
			}
		}

		/// <summary>
		/// Gets and sets the Point component of the AnchorPoint 
		/// </summary>
		[Browsable(false)]
		public Point Point
		{
			get{ return _point ;}
			set
			{
				_point = value;
			}
		}

		/// <summary>
		/// Specifies whether this AnchorPoint contains the same coordinates and AnchorStyles as the specified Object.
		/// </summary>
		/// <param name="obj">The Object to test</param>
		/// <returns>This method returns true if obj is a AnchorPoint and has the same coordinates and AnchorStyles as this AnchorPoint.</returns>
		public override bool Equals(object obj)
		{
			if ( obj is AnchorPoint ) return this == (AnchorPoint)obj;
			return false;
		}

		/// <summary>
		/// Returns a hash code for this AnchorPoint object.
		/// </summary>
		/// <returns>An integer value that specifies a hash value for this AnchorPoint object.</returns>
		public override int GetHashCode()
		{
			return _point.GetHashCode()^_anchor.GetHashCode();
		}

		#region operator AnchorPoint/PointF/Point/PointF

		/// <summary>
		/// Converts an AnchorPoint object to a Point object
		/// </summary>
		/// <param name="point">AnchorPoint to convert to a Point object</param>
		/// <returns>This operator returns the converted Point object</returns>
		public static implicit operator Point(	AnchorPoint point )
		{
			return point.Point;
		}

		/// <summary>
		/// Converts an AnchorPoint object to a Point object
		/// </summary>
		/// <param name="point">AnchorPoint to convert to a Point object</param>
		/// <returns>This operator returns the converted Point object</returns>
		public static Point ToPoint(	AnchorPoint point )
		{
			return point.Point;
		}

		/// <summary>
		/// Converts an Point object to an AnchorPoint object
		/// </summary>
		/// <param name="point">A Point to convert to an AnchorPoint object</param>
		/// <returns>This operator returns the converted AnchorPoint object</returns>
		public static implicit operator AnchorPoint(Point point )
		{
			return new AnchorPoint(point );
		}
		/// <summary>
		/// Converts an Point object to an AnchorPoint object
		/// </summary>
		/// <param name="point">A Point to convert to an AnchorPoint object</param>
		/// <returns>This operator returns the converted AnchorPoint object</returns>
		public static AnchorPoint ToAnchorPoint( Point point )
		{
			return new AnchorPoint( point );
		}

		#endregion 

		#region operator ==
		/// <summary>
		/// Compares two AnchorPoint objects. The result specifies whether the values of 
		/// the X and Y properties of the two AnchorPoint objects are equal.
		/// </summary>
		/// <param name="left">An AnchorPoint to compare.</param>
		/// <param name="right">An AnchorPoint to compare.</param>
		/// <returns>This operator returns true if the X, Y and Anchor values of left and right are equal; otherwise, false.</returns>
		public static bool operator ==(	AnchorPoint left,AnchorPoint right	)
		{
			return left.X == right.X && left.Y == right.Y && left.Anchor == right.Anchor;
		}

		/// <summary>
		/// Compares X and Y values of an AnchorPoint and Point object. The result specifies whether the values 
		/// of the X and Y properties of left and right are equal.
		/// </summary>
		/// <param name="left">An AnchorPoint to compare.</param>
		/// <param name="right">A Point to compare.</param>
		/// <returns>This operator returns true if the X and Y values of left and right are equal; otherwise, false.</returns>
		public static bool operator ==(	AnchorPoint left,Point right	)
		{
			return left.X == right.X && left.Y == right.Y;
		}

		/// <summary>
		/// Compares X and Y values of an Point and AnchorPoint object. The result specifies whether the values 
		/// of the X and Y properties of left and right are equal.
		/// </summary>
		/// <param name="left">A Point to compare.</param>
		/// <param name="right">An AnchorPoint to compare.</param>
		/// <returns>This operator returns true if the X and Y values of left and right are equal; otherwise, false.</returns>
		public static bool operator ==(	Point left,AnchorPoint right	)
		{
			return left.X == right.X && left.Y == right.Y;
		}

		#endregion 

		#region operator !=
		/// <summary>
		/// Compares two Point objects. The result specifies whether the values of the X, Y or Anchor 
		/// properties of the two AnchorPoint objects are unequal.
		/// </summary>
		/// <param name="left">An AnchorPoint to compare.</param>
		/// <param name="right">An AnchorPoint to compare.</param>
		/// <returns>This operator returns true if the values of either the X, Y or Anchor properties of left and right differ; otherwise, false.</returns>
		public static bool operator !=(	AnchorPoint left,AnchorPoint right	)
		{
			return left.X != right.X || left.Y != right.Y||left.Anchor != right.Anchor;
		}

		/// <summary>
		/// Compares two Point objects. The result specifies whether the values of the X or Y 
		/// properties of the two AnchorPoint objects are unequal.
		/// </summary>
		/// <param name="left">An AnchorPoint to compare.</param>
		/// <param name="right">A Point to compare.</param>
		/// <returns>This operator returns true if the values of either the X or Y properties of left and right differ; otherwise, false.</returns>
		public static bool operator !=(	AnchorPoint left,Point right	)
		{
			return left.X != right.X || left.Y != right.Y;
		}
		/// <summary>
		/// Compares two Point objects. The result specifies whether the values of the X or Y 
		/// properties of the two AnchorPoint objects are unequal.
		/// </summary>
		/// <param name="left">An AnchorPoint to compare.</param>
		/// <param name="right">A Point to compare.</param>
		/// <returns>This operator returns true if the values of either the X or Y properties of left and right differ; otherwise, false.</returns>
		public static bool operator !=(	Point left,AnchorPoint right	)
		{
			return left.X != right.X || left.Y != right.Y;
		}

		#endregion 

		#region operator+
//		/// <summary>
//		/// Translates an <c>AnchorPoint</c> by a given <c>Size</c>.
//		/// </summary>
//		/// <param name="point">The AnchorPoint to translate.</param>
//		/// <param name="size">A Size that specifies the pair of numbers to add to the coordinates <c>point</c>.</param>
//		/// <returns>The translated AnchorPoint structure.</returns>
//		public static AnchorPoint operator +(	AnchorPoint point,	Size size )
//		{
//			return new AnchorPoint(point.X + size.Width, point.Y+ size.Height);
//		}
//
//		/// <summary>
//		/// Translates an <c>AnchorPoint</c> by a given <c>Size</c>.
//		/// </summary>
//		/// <param name="point">The AnchorPoint to translate.</param>
//		/// <param name="size">A Size that specifies the pair of numbers to add to the coordinates <c>point</c>.</param>
//		/// <returns>The translated AnchorPoint structure.</returns>
//		public static AnchorPoint Add(	AnchorPoint point,	Size size )
//		{
//			return new AnchorPoint(point.X + size.Width, point.Y+ size.Height);
//		}
//
//		/// <summary>
//		/// Translates an <c>AnchorPoint</c> by a given <c>Size</c>.
//		/// </summary>
//		/// <param name="size">A Size that specifies the pair of numbers to add to the coordinates <c>point</c>.</param>
//		/// <param name="point">The AnchorPoint to translate.</param>
//		/// <returns>The translated AnchorPoint structure.</returns>
//		public static AnchorPoint operator +(	Size size, AnchorPoint point )
//		{
//			return new AnchorPoint(point.X + size.Width, point.Y+ size.Height);
//		}
//		/// <summary>
//		/// Translates an <c>AnchorPoint</c> by a given <c>Size</c>.
//		/// </summary>
//		/// <param name="size">A Size that specifies the pair of numbers to add to the coordinates <c>point</c>.</param>
//		/// <param name="point">The AnchorPoint to translate.</param>
//		/// <returns>The translated AnchorPoint structure.</returns>
//		public static AnchorPoint Add(	Size size, AnchorPoint point )
//		{
//			return new AnchorPoint(point.X + size.Width, point.Y+ size.Height);
//		}
//
//		public static AnchorPoint operator +(	AnchorPoint point1,	AnchorPoint point2 )
//		{
//			return new AnchorPoint(point1.X + point2.X, point1.Y+ point1.Y);
//		}
//		public static AnchorPoint Add(	AnchorPoint point1,	AnchorPoint point2 )
//		{
//			return new AnchorPoint(point1.X + point2.X, point1.Y+ point1.Y);
//		}
//
//		public static AnchorPoint operator +(	AnchorPoint point1,	Point point2 )
//		{
//			return new AnchorPoint(point1.X + point2.X, point1.Y+ point1.Y);
//		}
//		public static AnchorPoint Add(	AnchorPoint point1,	Point point2 )
//		{
//			return new AnchorPoint(point1.X + point2.X, point1.Y+ point1.Y);
//		}
//
//		public static AnchorPoint operator +(	Point point1,	AnchorPoint point2 )
//		{
//			return new AnchorPoint(point1.X + point2.X, point1.Y+ point1.Y);
//		}
//		public static AnchorPoint Add(	Point point1,	AnchorPoint point2 )
//		{
//			return new AnchorPoint(point1.X + point2.X, point1.Y+ point1.Y);
//		}

		#endregion 

		#region operator-
//		public static AnchorPoint operator -(	AnchorPoint point,	Size size )
//		{
//			return new AnchorPoint(point.X - size.Width, point.Y - size.Height);
//		}
//		public static AnchorPoint Subtract(	AnchorPoint point,	Size size )
//		{
//			return new AnchorPoint(point.X - size.Width, point.Y - size.Height);
//		}
//		public static AnchorPoint operator -(	Size size, AnchorPoint point )
//		{
//			return new AnchorPoint(point.X - size.Width, point.Y- size.Height);
//		}
//		public static AnchorPoint Subtract(	Size size, AnchorPoint point )
//		{
//			return new AnchorPoint(point.X - size.Width, point.Y- size.Height);
//		}
//
//		public static AnchorPoint operator -(	AnchorPoint point1,	AnchorPoint point2 )
//		{
//			return new AnchorPoint(point1.X - point2.X, point1.Y - point1.Y);
//		}
//		public static AnchorPoint Subtract(	AnchorPoint point1,	AnchorPoint point2 )
//		{
//			return new AnchorPoint(point1.X - point2.X, point1.Y - point1.Y);
//		}
//
//		public static AnchorPoint operator -(AnchorPoint point1,	Point point2 )
//		{
//			return new AnchorPoint(point1.X - point2.X, point1.Y - point1.Y);
//		}
//		public static AnchorPoint Subtract(AnchorPoint point1,	Point point2 )
//		{
//			return new AnchorPoint(point1.X - point2.X, point1.Y - point1.Y);
//		}
//
//		public static AnchorPoint operator -(	Point point1,	AnchorPoint point2 )
//		{
//			return new AnchorPoint(point1.X - point2.X, point1.Y - point1.Y);
//		}
//		public static AnchorPoint Subtract(	Point point1,	AnchorPoint point2 )
//		{
//			return new AnchorPoint(point1.X - point2.X, point1.Y - point1.Y);
//		}
		#endregion 

	}


}
